package com.tbs.overlay;

import java.io.IOException;
import java.io.InputStream;
import java.util.Timer;
import java.util.TimerTask;

import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.droidprojects.spotifytray.controller.MockPlaylist;
import com.droidprojects.spotifytray.controller.MockPlaylist.MockPlaylistListener;
import com.tbs.overlayservice.R;

@SuppressWarnings("deprecation")
public class PlayerService extends Service
							implements MockPlaylistListener{

	public enum OverlayMode {
		APP,
		HOME_SHOW
	}

	// 
	private static final int TRAY_HIDDEN_FRACTION 			= 6; 	// Controls fraction of the tray hidden when open
	private static final int TRAY_MOVEMENT_REGION_FRACTION 	= 6;	// Controls fraction of y-axis on screen within which the tray stays.
	private static final int TRAY_CROP_FRACTION 			= 12;	// Controls fraction of the tray chipped at the right end.
	private static final int ANIMATION_FRAME_RATE 			= 30;	// Animation frame rate per second.
	private static final int TRAY_DIM_X_DP 					= 170;	// Width of the tray in dps
	private static final int TRAY_DIM_Y_DP 					= 160; 	// Height of the tray in dps
	private static final int BUTTONS_DIM_Y_DP 				= 27;	// Height of the buttons in dps
	public static final int PADDING = 5;
	
	// Layout containers for various widgets
	private WindowManager 				mWindowManager;			// Reference to the window
	private WindowManager.LayoutParams 	mRootLayoutParams;		// Parameters of the root layout
	private RelativeLayout 				mRootLayout;			// Root layout
	private RelativeLayout 				mContentContainerLayout;// Contains everything other than buttons and song info
	private RelativeLayout 				mLogoLayout;			// Contains Cpotify logo
	private RelativeLayout 				mAlbumCoverLayout;		// Contains album cover of the active song
	private RelativeLayout 				mAlbumCoverHelperLayout;// Contains cover of the previous song. This helps with fade animations.
	private LinearLayout 				mPlayerButtonsLayout;	// Contains playback buttons
	private LinearLayout 				mSongInfoLayout;		// Contains Text information on the current song
	private ImageView 					mTrayOpener;		// Contains Text information on the current song
	private ImageView 					mTrayOpenerRight;
	

	// Widgets
	private ImageButton mPlaySongButton;
	private ImageButton mPauseSongButton;
	private TextView mSongTitleView;
	private TextView mSingerView;
	
	// Variables that control drag
	private int mStartDragX;
	//private int mStartDragY; // Unused as yet
	private int mPrevDragX;
	private int mPrevDragY;
	
	private boolean mIsTrayOpen = true;
	
	// Controls for animations
	private Timer 					mTrayAnimationTimer;
	private TrayAnimationTimerTask 	mTrayAnimationTimerTask;
	private Handler 				mAnimationHandler = new Handler();
	
	// Mock song data
	private MockPlaylist mPlaylist;
	private boolean mIsSlidingX = true;
	private boolean mIsFirstTimeMove = false;
	protected boolean mIsLeftSide = true;
	protected boolean mClosed = false;
	protected OverlayMode mOverlayMode = OverlayMode.APP;

	@Override
	public IBinder onBind(Intent intent) {
		// Not used
		return null;
	}

	@Override
	public void onCreate() {
		
		mOverlayMode = OverlayMode.HOME_SHOW;

		// Get references to all the views and add them to root view as needed.
		mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

		mRootLayout = (RelativeLayout) LayoutInflater.from(this).
				inflate(R.layout.service_player, null);
		mContentContainerLayout = (RelativeLayout) mRootLayout.findViewById(R.id.content_container);
		mContentContainerLayout.setOnTouchListener(new TrayTouchListener());
		
		mLogoLayout = (RelativeLayout) mRootLayout.findViewById(R.id.logo_layout);
		mAlbumCoverLayout = (RelativeLayout) mRootLayout.findViewById(R.id.cover_layout);
		mAlbumCoverHelperLayout = (RelativeLayout) mRootLayout.findViewById(R.id.cover_helper_layout);
		mTrayOpener = (ImageView) mRootLayout.findViewById(R.id.tray_opener);
		mTrayOpenerRight = (ImageView) mRootLayout.findViewById(R.id.tray_opener_right);

		mPlayerButtonsLayout = (LinearLayout) LayoutInflater.from(this).
				inflate(R.layout.viewgroup_player_buttons, null);
		mRootLayout.addView(mPlayerButtonsLayout);
		
		mSongInfoLayout = (LinearLayout) LayoutInflater.from(this).
				inflate(R.layout.viewgroup_song_info, null);
		mRootLayout.addView(mSongInfoLayout);
		
		mRootLayoutParams = new WindowManager.LayoutParams(
				Utils.dpToPixels(TRAY_DIM_X_DP, getResources()),
				Utils.dpToPixels(TRAY_DIM_Y_DP, getResources()),
				WindowManager.LayoutParams.TYPE_PHONE, 
				WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 
				| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, 
				PixelFormat.TRANSLUCENT);

		mRootLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
		mWindowManager.addView(mRootLayout, mRootLayoutParams);
		
		mPlaySongButton = (ImageButton) mPlayerButtonsLayout.findViewById(R.id.button_play);
		mPauseSongButton = (ImageButton) mPlayerButtonsLayout.findViewById(R.id.button_pause);
		mSongTitleView = (TextView) mSongInfoLayout.findViewById(R.id.song_name);
		mSingerView = (TextView) mSongInfoLayout.findViewById(R.id.singer_name);
		
		mPlaylist = new MockPlaylist(this);
		
		// Post these actions at the end of looper message queue so that the layout is
		// fully inflated once these functions execute
		mRootLayout.postDelayed(new Runnable() {
			@Override
			public void run() {
				
				// Reusable variables
				RelativeLayout.LayoutParams params;
				InputStream is;
				Bitmap bmap;
				
				//tray opener
				params = (RelativeLayout.LayoutParams) mTrayOpener.getLayoutParams();
				params.width = mRootLayoutParams.width/TRAY_HIDDEN_FRACTION;
				params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,0);
				mTrayOpener.setLayoutParams(params);
				mTrayOpener.requestLayout();
				
				is = getResources().openRawResource(R.drawable.spot_bg);
				int containerNewWidth = (TRAY_CROP_FRACTION-1)*mLogoLayout.getHeight()/TRAY_CROP_FRACTION;
				bmap = Utils.loadMaskedBitmap(is, mLogoLayout.getHeight(), containerNewWidth);
				params = (RelativeLayout.LayoutParams) mLogoLayout.getLayoutParams();
				params.width = (bmap.getWidth() * mLogoLayout.getHeight()) / bmap.getHeight();
				//params.addRule(RelativeLayout.ALIGN_PARENT_LEFT,0);
				params.addRule(RelativeLayout.RIGHT_OF,R.id.tray_opener);
				mLogoLayout.setLayoutParams(params);
				mLogoLayout.requestLayout();
				mLogoLayout.setBackgroundDrawable(new BitmapDrawable(getResources(), bmap));
				
				// Setup background album cover
				is=null;
				try {
					is = getAssets().open(mPlaylist.getCurrentSongInfo().mAlbumCoverPath);
				} catch (IOException e) {
					e.printStackTrace();
				}
				bmap = Utils.loadMaskedBitmap(is, mAlbumCoverLayout.getHeight(), containerNewWidth);
				params = (RelativeLayout.LayoutParams) mAlbumCoverLayout.getLayoutParams();
				params.width = (bmap.getWidth() * mAlbumCoverLayout.getHeight()) / bmap.getHeight();
				//params.addRule(RelativeLayout.ALIGN_PARENT_LEFT,0);
				params.addRule(RelativeLayout.RIGHT_OF,R.id.tray_opener);
				mAlbumCoverLayout.setLayoutParams(params);
				mAlbumCoverLayout.requestLayout();
				mAlbumCoverHelperLayout.setLayoutParams(params);
				mAlbumCoverHelperLayout.requestLayout();
				mAlbumCoverLayout.setBackgroundDrawable(new BitmapDrawable(getResources(), bmap));

				// Setup playback buttons
				params = new RelativeLayout.LayoutParams(
						RelativeLayout.LayoutParams.MATCH_PARENT, 
						Utils.dpToPixels(BUTTONS_DIM_Y_DP, getResources()));
				params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
				params.leftMargin = mRootLayout.getWidth()/TRAY_HIDDEN_FRACTION;
				mRootLayout.updateViewLayout(mPlayerButtonsLayout, params);
				
				// setup song info views
				params = new RelativeLayout.LayoutParams(
						RelativeLayout.LayoutParams.MATCH_PARENT, 
						RelativeLayout.LayoutParams.WRAP_CONTENT);
				//params.addRule(RelativeLayout.ALIGN_RIGHT, R.id.tray_opener);
				params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
				int marg = Utils.dpToPixels(5, getResources());
				params.setMargins(
						marg/2 + mRootLayout.getWidth()/TRAY_HIDDEN_FRACTION, 
						marg, 
						marg*3, 
						marg);
				mRootLayout.updateViewLayout(mSongInfoLayout, params);
				mSongTitleView.setText(mPlaylist.getCurrentSongInfo().mTitle);
				mSingerView.setText(mPlaylist.getCurrentSongInfo().mSinger);
				
				
				// Setup the root layout
				mRootLayoutParams.x = getResources().getDisplayMetrics().widthPixels -mRootLayoutParams.width;
				mRootLayoutParams.y = getApplicationContext().getResources().getDisplayMetrics().heightPixels - 2*mLogoLayout.getHeight()-PADDING;
				
				updateViewLayout();
				
				// Make everything visible
				mRootLayout.setVisibility(View.VISIBLE);
				
				// Animate the Tray
				mTrayAnimationTimerTask = new TrayAnimationTimerTask();
				mTrayAnimationTimer = new Timer();
				mTrayAnimationTimer.schedule(mTrayAnimationTimerTask, 0, ANIMATION_FRAME_RATE);
			}
		}, ANIMATION_FRAME_RATE);
	}

	// The phone orientation has changed. Update the widget's position.
	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);
		if (mIsTrayOpen)
			mRootLayoutParams.x = -mRootLayout.getWidth()/TRAY_HIDDEN_FRACTION;
		else
			mRootLayoutParams.x = -mLogoLayout.getWidth();
		mRootLayoutParams.y = (getResources().getDisplayMetrics().heightPixels-mRootLayout.getHeight()) / 2;
		updateViewLayout();
		animateButtons();
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		
		
		if (intent!=null&&intent.getBooleanExtra("stop_service", false)){
			// If it's a call from the notification, stop the service.
			stopSelf();
		}else{
			// Make the service run in foreground so that the system does not shut it down.
			Intent notificationIntent = new Intent(this, PlayerService.class);
			notificationIntent.putExtra("stop_service", true);
			PendingIntent pendingIntent = PendingIntent.getService(this, 0, notificationIntent, 0);
			Notification notification = new Notification(
					R.drawable.ic_launcher, 
					"Spotify tray launched",
			        System.currentTimeMillis());
			notification.setLatestEventInfo(
					this, 
					"Spotify tray",
			        "Tap to close the widget.", 
			        pendingIntent);
			startForeground(86, notification);
		}
		return START_STICKY;
	}

	// The app is closing.
	@Override
	public void onDestroy() {
		mPlaylist.stopCurrentSong();
		if (mRootLayout != null)
			mWindowManager.removeView(mRootLayout);
	}

	// Drags the tray as per touch info
	private void dragTray(int action, int x, int y){
		switch (action){
		case MotionEvent.ACTION_DOWN:
			
			mIsFirstTimeMove = true;
			// Cancel any currently running animations/automatic tray movements.
			if (mTrayAnimationTimerTask!=null){
				mTrayAnimationTimerTask.cancel();
				mTrayAnimationTimer.cancel();
			}
			
			// Store the start points
			mStartDragX = x;
			//mStartDragY = y;
			mPrevDragX = x;
			mPrevDragY = y;
			break;
			
		case MotionEvent.ACTION_MOVE:
			
			// Calculate position of the whole tray according to the drag, and update layout.
			float deltaX = x-mPrevDragX;
			float deltaY = y-mPrevDragY;
			if (mOverlayMode==OverlayMode.APP) {
				deltaY = deltaY>=0?0:deltaY;				
			}
			if (mIsFirstTimeMove) {
				mIsSlidingX =  Math.abs(deltaY)<=Math.abs(deltaX);
				mIsFirstTimeMove = false;
			}
			
			if (mIsSlidingX) {
				mRootLayoutParams.x += deltaX;				
			}
			else{
				mRootLayoutParams.y += deltaY;
/*				LayoutParams ml = mLogoLayout.getLayoutParams();
				ml.width += 5;
				ml.height += 5;
				mLogoLayout.setLayoutParams(ml);
				mLogoLayout.requestLayout();*/
			}

			mPrevDragX = x;
			mPrevDragY = y;
			animateButtons();
			updateViewLayout();

			break;
			
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_CANCEL:
			mIsFirstTimeMove = true;
			setOverlayPlace(x,y);
			
			//animation
			mTrayAnimationTimerTask = new TrayAnimationTimerTask();
			mTrayAnimationTimer = new Timer();
			mTrayAnimationTimer.schedule(mTrayAnimationTimerTask, 0, ANIMATION_FRAME_RATE);
			break;
		}
	}

	@SuppressLint("NewApi")
	private void updateViewLayout() {
		try {
			mWindowManager.updateViewLayout(mRootLayout, mRootLayoutParams);						
		} catch (java.lang.IllegalArgumentException e) {
			e.printStackTrace();
		}

		float alpha = 1.0f;
		float distance = 1;
		float remain = 1;
		switch (mOverlayMode) {
		case APP:
			int landMarkX = getResources().getDisplayMetrics().widthPixels -mRootLayoutParams.width;
			if (mRootLayoutParams.x-landMarkX>0) {
				distance = mRootLayoutParams.width;
				remain = getResources().getDisplayMetrics().widthPixels - mRootLayoutParams.x;
			}
			else{
				distance  = landMarkX;
				remain = mRootLayoutParams.x;
			}

			break;
		case HOME_SHOW:
			int screenHeight = getResources().getDisplayMetrics().heightPixels;
			distance = screenHeight/TRAY_MOVEMENT_REGION_FRACTION+mRootLayoutParams.width;
			remain = screenHeight-mRootLayoutParams.y;
			//(mRootLayoutParams.y>((TRAY_MOVEMENT_REGION_FRACTION-1)*screenHeight)/TRAY_MOVEMENT_REGION_FRACTION-mRootLayoutParams.width);
			
			break;
		default:
			break;
			

		}
		alpha = remain/distance;
		alpha = alpha<0.0000001?0:alpha;
		if (Build.VERSION.SDK_INT < 11) {
			final AlphaAnimation animation = new AlphaAnimation(alpha, alpha);
			long duration = 0;
			animation.setDuration(duration );
			animation.setFillAfter(true);
			//mContentContainerLayout.startAnimation(animation);
		}else{
			//mContentContainerLayout.setAlpha(alpha);
		}
	}

	// Listens to the touch events on the tray.
	private class TrayTouchListener implements OnTouchListener {
		@Override
		public boolean onTouch(View v, MotionEvent event) {

			final int action = event.getActionMasked();

			switch (action) {
			case MotionEvent.ACTION_DOWN: 
			case MotionEvent.ACTION_MOVE:
			case MotionEvent.ACTION_UP:
			case MotionEvent.ACTION_CANCEL:
				// Filter and redirect the events to dragTray()
				dragTray(action, (int)event.getRawX(), (int)event.getRawY());
				break;
			default:
				return false;
			}
			return true;

		}
	}
	
	// Timer for animation/automatic movement of the tray.
	private class TrayAnimationTimerTask extends TimerTask{
		
		// Ultimate destination coordinates toward which the tray will move
		int mDestX;
		int mDestY;
		
		public TrayAnimationTimerTask(){
			
			// Setup destination coordinates based on the tray state. 
			super();
			//origin
			/*if (!mIsTrayOpen){
				mDestX = -mLogoLayout.getWidth();
			}else{
				mDestX = -mRootLayout.getWidth()/TRAY_HIDDEN_FRACTION;
			}*/
			//align right
			setDestinationCordinate();
			
		}
		
		private void setDestinationCordinate() {
			int screenHeight = getResources().getDisplayMetrics().heightPixels;

			switch (mOverlayMode) {
			case APP:
				//mIsLeftSide = false;
				if (mClosed) {
					mDestX = mIsLeftSide?-mLogoLayout.getWidth():screenHeight+2*mRootLayoutParams.width;					
				}
				else{
					mDestX = getResources().getDisplayMetrics().widthPixels -mRootLayoutParams.width;					
				}
				mDestY = screenHeight - 2*mLogoLayout.getHeight()-PADDING;
				// Keep lower edge of the widget within the lower limit of screen
				//mDestY = Math.min(((TRAY_MOVEMENT_REGION_FRACTION-1)*screenHeight)/TRAY_MOVEMENT_REGION_FRACTION - mRootLayout.getHeight(),screenHeight/TRAY_MOVEMENT_REGION_FRACTION);
				break;
			case HOME_SHOW:
				if (!mIsTrayOpen){
					if (mIsLeftSide) {
						mTrayOpener.setVisibility(View.GONE);
						mTrayOpenerRight.setVisibility(View.VISIBLE);
						mDestX = -mLogoLayout.getWidth();
					}
					else{
						mTrayOpenerRight.setVisibility(View.GONE);
						mTrayOpener.setVisibility(View.VISIBLE);
						mDestX = getResources().getDisplayMetrics().widthPixels-mRootLayoutParams.width/TRAY_HIDDEN_FRACTION;
					}
					
				}else{
					if (mIsLeftSide) {
						mDestX = 0;
					}
					else{
						mDestX = mWindowManager.getDefaultDisplay().getWidth() -mRootLayoutParams.width;
					}
					mTrayOpener.setVisibility(View.GONE);
					mTrayOpenerRight.setVisibility(View.GONE);
				}
				
				// Keep upper edge of the widget within the upper limit of screen
				
				if (mClosed) {
					mDestY = screenHeight;					
				}
				else{
					mDestY = Math.max(screenHeight/TRAY_MOVEMENT_REGION_FRACTION,mRootLayoutParams.y);
					// Keep lower edge of the widget within the lower limit of screen
					mDestY = Math.min(((TRAY_MOVEMENT_REGION_FRACTION-1)*screenHeight)/TRAY_MOVEMENT_REGION_FRACTION - mRootLayoutParams.width,mDestY);
				}
				
				break;
			default:
				break;
			}
		}

		// This function is called after every frame.
		@Override
		public void run() {
			
			// handler is used to run the function on main UI thread in order to
			// access the layouts and UI elements.
			mAnimationHandler.post(new Runnable() {
				@Override
				public void run() {
					
					// Update coordinates of the tray
					mRootLayoutParams.x = (2*(mRootLayoutParams.x-mDestX))/3 + mDestX;
					mRootLayoutParams.y = (2*(mRootLayoutParams.y-mDestY))/3 + mDestY;
					updateViewLayout();
					animateButtons();
					
					// Cancel animation when the destination is reached
					if (Math.abs(mRootLayoutParams.x-mDestX)<2 && Math.abs(mRootLayoutParams.y-mDestY)<2){
						TrayAnimationTimerTask.this.cancel();
						mTrayAnimationTimer.cancel();
						if (mClosed) {
							stopSelf();
						}
					}
				}
			});
		}
	}
	
	// This function animates the buttons based on the position of the tray.
	private void animateButtons(){
		
		// Animate only if the tray is between open and close state.
		if (mRootLayoutParams.x < -mRootLayout.getWidth()/TRAY_HIDDEN_FRACTION){
			
			// Scale the distance between open and close states to 0-1. 
			float relativeDistance = (mRootLayoutParams.x + mLogoLayout.getWidth())/(float)
					(-mRootLayout.getWidth()/TRAY_HIDDEN_FRACTION + mLogoLayout.getWidth());
			
			// Limit it to 0-1 if it goes beyond 0-1 for any reason.
			relativeDistance=Math.max(relativeDistance, 0);
			relativeDistance=Math.min(relativeDistance, 1);
			
			// Setup animations
			AnimationSet animations = new AnimationSet(true);
			animations.setFillAfter(true);
			Animation animationAlpha = new AlphaAnimation(
					relativeDistance, 
					relativeDistance);
			animations.addAnimation(animationAlpha);

			Animation animationScale = new ScaleAnimation(
					relativeDistance, 
					relativeDistance, 
					relativeDistance, 
					relativeDistance);
			animations.addAnimation(animationScale);
			
			// Play the animations
			mPlayerButtonsLayout.startAnimation(animations);
			mSongInfoLayout.startAnimation(animations);
			mAlbumCoverLayout.startAnimation(animationAlpha);
			mRootLayout.startAnimation(animations);
		}else{
			
			// Clear all animations if the tray is being dragged - that is, when it is beyond the
			// normal open state.
			mPlayerButtonsLayout.clearAnimation();
			mSongInfoLayout.clearAnimation();
			mAlbumCoverLayout.clearAnimation();
			mRootLayout.clearAnimation();
		}
		
		scaleRootLayout();
	}
	
	private void scaleRootLayout() {

		// Scale the distance between open and close states to 0-1. 
		//float relativeDistance = (mRootLayoutParams.x + mLogoLayout.getWidth())/(float)(-mRootLayout.getWidth()/TRAY_HIDDEN_FRACTION + mLogoLayout.getWidth());
		int screenHeight = getResources().getDisplayMetrics().heightPixels;

		float relativeDistance = (screenHeight - mRootLayoutParams.y )/(float)screenHeight;
		
		// Limit it to 0-1 if it goes beyond 0-1 for any reason.
//		relativeDistance=Math.max(relativeDistance, 0);
//		relativeDistance=Math.min(relativeDistance, 1);
		
		// Setup animations
		AnimationSet animations = new AnimationSet(true);
		animations.setFillAfter(true);
		Animation animationAlpha = new AlphaAnimation(
				relativeDistance, 
				relativeDistance);
		animations.addAnimation(animationAlpha);

		Animation animationScale = new ScaleAnimation(
				relativeDistance, 
				relativeDistance, 
				relativeDistance, 
				relativeDistance);
		animations.addAnimation(animationScale);
		//mRootLayoutParams.height +=2;
		//mRootLayoutParams.width +=2;
		// Play the animations
		//mWindowManager.updateViewLayout(mRootLayout, mRootLayoutParams);
		mContentContainerLayout.startAnimation(animations);
	}

	// Load new album cover image
	private void changeSongDisplayInfo(){
		
		InputStream is=null;
		try {
			is = getAssets().open(mPlaylist.getCurrentSongInfo().mAlbumCoverPath);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		// Load new bitmap
		Bitmap bmap = Utils.loadMaskedBitmap(is, mAlbumCoverLayout.getHeight(), mAlbumCoverLayout.getWidth());
		
		// Change backgrounds
		mAlbumCoverHelperLayout.setBackgroundDrawable(mAlbumCoverLayout.getBackground());
		mAlbumCoverLayout.setBackgroundDrawable(new BitmapDrawable(getResources(), bmap));
		
		// Animate the two layouts in order to achieve the fade in/fade out effect.
		// First normalise the distance between open and closed states (0-1)
		float relativeDistance = (mRootLayoutParams.x + mLogoLayout.getWidth())/(float)
				(-mRootLayout.getWidth()/TRAY_HIDDEN_FRACTION + mLogoLayout.getWidth());
		relativeDistance=Math.max(relativeDistance, 0);
		relativeDistance=Math.min(relativeDistance, 1);
		
		// Then use it to set final alpha in the animation.
		Animation fadeOutAnim = new AlphaAnimation(relativeDistance,0.f);
		fadeOutAnim.setFillAfter(true);
		fadeOutAnim.setDuration(1000);
		Animation fadeInAnim = new AlphaAnimation(0.f,relativeDistance);
		fadeInAnim.setFillAfter(true);
		fadeInAnim.setDuration(1000);
		mAlbumCoverHelperLayout.startAnimation(fadeOutAnim);
		mAlbumCoverLayout.startAnimation(fadeInAnim);
		
		// Set new song info
		mSongTitleView.setText(mPlaylist.getCurrentSongInfo().mTitle);
		mSingerView.setText(mPlaylist.getCurrentSongInfo().mSinger);
	}
	
	/**************************** Callbacks **************************************/
	
	// Play current song
	public void playButtonClicked(View view){
		mPlaySongButton.setVisibility(View.INVISIBLE);
		mPauseSongButton.setVisibility(View.VISIBLE);
		mPlaylist.playCurrentSong();
	}

	// Pause current song
	public void pauseButtonClicked(View view){
		mPauseSongButton.setVisibility(View.INVISIBLE);
		mPlaySongButton.setVisibility(View.VISIBLE);
		mPlaylist.pauseCurrentSong();
	}
	
	// Play next song
	public void nextButtonClicked(View view){
		mPlaySongButton.setVisibility(View.INVISIBLE);
		mPauseSongButton.setVisibility(View.VISIBLE);
		mPlaylist.playNextSong();
		changeSongDisplayInfo();
	}
	
	// Play previous song
	public void prevButtonClicked(View view){
		mPlaySongButton.setVisibility(View.INVISIBLE);
		mPauseSongButton.setVisibility(View.VISIBLE);
		mPlaylist.playPreviousSong();
		changeSongDisplayInfo();
	}

	
	// Mock song playlist callback - Notifies the UI about song progress. 
	@Override
	public void updateSongProgress(int playheadPosition) {
		// TODO - Will be implemented later
	}

	// Mock song playlist callback - Notifies the UI to update song info. Current song has changed.
	@Override
	public void startedNextSong() {
		changeSongDisplayInfo();
	}

	// Mock song playlist callback - Provides the UI thread handler so that the callee thread could update UI
	@Override
	public Handler getHandler() {
		return new Handler();
	}
	
	//-------------------new update --------------------


	private void setOverlayPlace(int x, int y) {
		boolean previousSide = mIsLeftSide;
		int screenHeight = getResources().getDisplayMetrics().heightPixels;
		int screenWidth = getResources().getDisplayMetrics().widthPixels;
		//boolean closeTray = !mIsTrayOpen;
		
		switch (mOverlayMode) {
		case APP:
			if (mIsSlidingX){
				mIsLeftSide = (x<screenWidth/2||(x-mStartDragX)<-screenWidth/3);
				mClosed = mIsLeftSide||(x>=screenWidth||(x-mStartDragX)>mRootLayoutParams.width/2);
			}
			break;
		case HOME_SHOW:

			if (mIsSlidingX){
				boolean resultAtLeft = mIsTrayOpen?(x-mStartDragX)<(2*mContentContainerLayout.getWidth()/9):(x-mStartDragX)<mContentContainerLayout.getWidth();
				boolean resultAtRight = mIsTrayOpen?(x-mStartDragX)<(-1*(2*mContentContainerLayout.getWidth()/9)):(x-mStartDragX)<-1*mAlbumCoverLayout.getWidth();
				mIsLeftSide = mIsLeftSide?resultAtLeft:resultAtRight;
				//Log.i("hung", "mIsLeftSide "+mIsLeftSide+ " mIsTrayOpen "+mIsTrayOpen+" with x "+x+" mStartDragX "+mStartDragX+ " (x-mStartDragX) "+(x-mStartDragX)+" (mAlbumCoverLayout.getWidth()/8) "+(mAlbumCoverLayout.getWidth()/8));
			}
			else{
				mClosed =  mRootLayoutParams.y>=((TRAY_MOVEMENT_REGION_FRACTION-1)*screenHeight)/TRAY_MOVEMENT_REGION_FRACTION-mRootLayout.getWidth();
			}
			
			//set opentray
			boolean sideKept = previousSide==mIsLeftSide;
			if (sideKept) {
				// When the tray is released, bring it back to "open" or "closed" state.
				if (mIsSlidingX&&(mIsLeftSide&&((mIsTrayOpen && (x-mStartDragX)<=0) ||
						(!mIsTrayOpen && (x-mStartDragX)>=0))))
					mIsTrayOpen = !mIsTrayOpen;
				
				if (mIsSlidingX&&(!mIsLeftSide&&((!mIsTrayOpen && (x-mStartDragX)<=0) ||
						(mIsTrayOpen && (x-mStartDragX)>=0))))
					mIsTrayOpen = !mIsTrayOpen;				
			}
			else{
				mIsTrayOpen = mIsLeftSide?mRootLayoutParams.x>=0:mRootLayoutParams.x<=screenWidth-mRootLayoutParams.width;
				//Log.i("hung", "mIsLeftSide "+mIsLeftSide+ " mIsTrayOpen "+mIsTrayOpen+" with x "+x+" screenWidth "+screenWidth+" mRootLayoutParams.width "+mRootLayoutParams.width);
			}
			
			break;
		default:
			break;
		}

	}
}
